package com.biboheart.adapter.compiler.grammar;

import com.biboheart.adapter.compiler.Grammar;
import com.biboheart.adapter.compiler.ast.Node;
import com.biboheart.adapter.compiler.enums.NodeType;
import com.biboheart.adapter.compiler.enums.TokenType;
import com.biboheart.adapter.compiler.grammar.*;
import com.biboheart.adapter.compiler.token.Token;
import com.biboheart.adapter.compiler.utils.TokenUtils;
import com.biboheart.adapter.support.enums.InstructEnum;

import java.util.ArrayList;
import java.util.List;

public class GrammarImpl implements Grammar {
    @Override
    public Node analysis(List<Token> tokenList) {
        Parser parser = new Parser(tokenList);
        parser.start();
        return parser.root;
    }

    // statements, expression, factor
    private static class Parser {
        private final Node root = new Node(NodeType.NODE_ROOT, null, new ArrayList<>(), null);
        private final List<Token> tokenList;

        public Parser(List<Token> tokenList) {
            this.tokenList = tokenList;
        }

        public void start() {
            if (null == tokenList || tokenList.isEmpty()) {
                return;
            }
            Node node = analysis(tokenList);
            if (null != node) {
                root.getChildren().add(node);
            }
        }

        // 分析
        private Node analysis(List<Token> tokenList) {
            if (null == tokenList || tokenList.isEmpty()) {
                return null;
            }
            Token token = TokenUtils.getLowestLevelToken(tokenList);
            Node node;
            Expression expression;
            TokenType tokenType = token.getType();
            if (TokenType.TOKEN_KEYWORD.equals(tokenType)) {
                if (InstructEnum.INSTRUCT_CASE.code().equals(token.getCode())) {
                    expression = new CaseExpression(tokenList);
                } else if (InstructEnum.INSTRUCT_ELSE.code().equals(token.getCode())) {
                    expression = new ElseExpression(tokenList);
                } else if (InstructEnum.INSTRUCT_WHEN.code().equals(token.getCode())) {
                    expression = new WhenExpression(tokenList);
                } else {
                    expression = new CommandExpression(tokenList);
                }
            } else {
                expression = new OperatorExpression(tokenList);
            }
            node = expression.parser();
            if (null == node) {
                return null;
            }
            List<Node> children = node.getChildren();
            if (children.isEmpty()) {
                return node;
            }
            for (Node child : children) {
                List<Token> expr = child.getExpression();
                boolean next = null != expr && !expr.isEmpty();
                if (!next) {
                    continue;
                }
                Node _node = analysis(expr);
                if (null != _node) {
                    child.setNodeType(_node.getNodeType());
                    child.setToken(_node.getToken());
                    child.setExpression(_node.getExpression());
                    child.setChildren(_node.getChildren());
                } else {
                    child.setToken(null);
                    child.setExpression(null);
                    child.setChildren(null);
                }
            }
            return node;
        }

        private Node statements(Token token) {
            return null;
        }

        private Node expression(Token token) {
            return null;
        }

        private Node factor(Token token) {
            return null;
        }
    }
}
